/**
 * 
 */
package os.filesystem.file;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import os.filesystem.file.exception.FSFileExistException;
import os.filesystem.file.exception.FSFileHierarchyException;
import os.filesystem.utils.FSString;

/**
 * Defines a directory.
 * 
 * @author Raghav Sidhanti
 * @since Mar 6, 2012 10:19:52 AM
 * 
 */
public abstract class Directory extends File {

	public static final String TYPE = "DIRECTORY";
	private static final long serialVersionUID = -1686308094553808200L;

	public Directory(String name, String creator) {
		super(name, creator);
	}

	private List<FileMeta> metas = new Vector<FileMeta>(3);

	public void add(FileMeta fm) throws FSFileExistException, FSFileHierarchyException {
		// Make sure file does not exist
		for (FileMeta m : metas) {
			if (m.getName().equals(fm.getName())) {
				throw new FSFileExistException("File: " + fm.getName() + " already exists.");
			}
		}
		// update absolute name
		fm.setAbsoluteName(FSString.fhsStringBuilder(getMeta().getAbsoluteName(), fm.getName()));
		if (isLogicalParent(fm)) {
			metas.add(fm);
		} else {
			throw new FSFileHierarchyException("Misplaced hierarchy. File: " + fm.getName() + " can not be added.");
		}
	}

	public boolean isLogicalParent(FileMeta fm) {
		String absName = getMeta().getAbsoluteName();
		if (fm.getAbsoluteName().startsWith(absName)) {
			if (fm.getAbsoluteName().substring(absName.length() + 1).contains(FSString.FILE_HIERARCHY_SEPERATOR)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Checks whether the given file name exists in the directory.
	 * 
	 * @param filename
	 * @return
	 */
	public boolean contains(String filename) {
		for (FileMeta fm : getFileMetas()) {
			if (fm.getName().equals(filename)) {
				return true;
			}
		}
		return false;
	}

	public String remove(String filename) throws FSFileHierarchyException {
		for (int index = 0; index < getFileMetas().size(); index++) {
			FileMeta fm = getFileMetas().get(index);
			if (fm.getName().equals(filename)) {
				String absName = fm.getAbsoluteName();
				getFileMetas().remove(index);
				return absName;
			}
		}

		throw new FSFileHierarchyException("Can not remove. No file: " + filename);
	}

	public List<FileMeta> getFileMetas() {
		return metas;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see os.filesystem.file.File#getType()
	 */
	@Override
	public String getType() {
		return TYPE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Directory) {
			Directory dir = (Directory) obj;
			// compare meta
			boolean sameMeta = getMeta().equals(dir.getMeta());
			boolean sameDirType = getDirectoryType().equals(dir.getDirectoryType());
			if (sameMeta && sameDirType) {
				Map<String, FileMeta> ht = new HashMap<String, FileMeta>(getFileMetas().size());
				for (FileMeta fm : getFileMetas()) {
					ht.put(fm.getName(), fm);
				}

				int len = dir.getFileMetas().size();
				for (FileMeta fm : dir.getFileMetas()) {
					FileMeta fmVal = ht.remove(fm.getName());
					if (fmVal == null) {
						return false;
					}
					len--;
				}

				if (len == 0 && ht.size() == 0) {
					return true;
				}

			}
		}
		return false;
	}

	public abstract String getDirectoryType();
}
